//练习数值计算题目，写一个命令行程序

/**
 * 计算一个数组的和
 * @param { Array<number> } arr 
 * @returns { number }
 */
function sum_of_array(arr) {
    return arr.reduce((value, last_result) => value + last_result, 0);
}

/**
 * 计算数组中子数组之和的最大值
 * @param { Array<number> } arr 
 * @returns { number }
 */
function sum_max_subset_of_array(arr) {
    let result;

    // 用两个 for 循环, 限定子数组的左右范围
    // 左范围
    for (let left = 0; left < arr.length; left ++) {
        // 右范围
        for (let right = left + 1; right < arr.length + 1; right ++) {
            const this_sum = sum_of_array(
                arr.slice(
                    Number(left), 
                    Number(right)
                )
            );

            if (result === undefined || result < this_sum) {
                result = this_sum;
            }
            
        }
    }

    if (result === undefined) {
        throw new Error("无法计算该数组!");
    }

    return result;
}



/*
这种程序，用最直观的方法去编程，最耗时的通常时对于素数的判断使用循环
改进方法：这里我们可以用到埃拉托斯特尼筛法，也就是我们常说的“埃氏筛”
算法原理：
埃拉托斯特尼筛法的基本思想是逐步标记掉非素数，从而筛选出素数。算法的步骤如下：

    初始化：创建一个列表，包含从2到nn 的所有整数。
    筛选：从最小的素数2开始，遍历列表，将2的倍数（除了2本身）标记为非素数。
    重复：接着找到下一个未被标记的数，这个数是下一个素数。然后，重复步骤2，将这个数的所有倍数（除了它本身）标记为非素数。
    继续：重复上述过程，直到你检查到列表中小于或等于 nn的所有数。因为如果 nn 是一个合数，它必有一个因子小于或等于它的平方根。
    输出：最后，未被标记的数就是素数。

算法步骤：
    创建列表：创建一个列表，包含从2到nn 的所有整数。
    标记2的倍数：将2的所有倍数（除了2本身）标记为非素数。
    寻找下一个素数：找到列表中下一个未被标记的数，记为 pp。
    标记pp的倍数：将 pp 的所有倍数（p2p2 到 nn 之间）标记为非素数。
    重复：重复步骤3和4，直到 p2>np2>n。
    输出素数：所有未被标记的数就是小于或等于 nn 的所有素数。
*/


/**
 * 检查一个数是否为素数
 */
function isPrime(num) {
    if (num <= 1) return false;
    if (num === 2) return true;
    if (num % 2 === 0) return false;
    for (let i = 3; i * i <= num; i += 2) {
        if (num % i === 0) return false;
    }
    return true;
}

/**
 * 输出从 from 到 to 内的所有素数，按每行5个打印出来
 */
function printPrimeNumber(from, to) {
    let result = [];
    from = Math.max(from, 2);

    for (let i = from; i <= to; i++) {
        if (isPrime(i)) {
            result.push(i);
        }
    }

    for (let i = 0; i < result.length; i += 5) {
        let output = result.slice(i, i + 5).join("\t");
        console.log(output);
    }
}

printPrimeNumber(0, 20000);